package com.gm.wj.service;

import com.gm.wj.config.RedisConfig;
import com.gm.wj.dao.SysFlowDAO;
import com.gm.wj.dao.SysOrderDAO;
import com.gm.wj.entity.*;
import com.gm.wj.redis.RedisService;
import com.gm.wj.util.JsonUtils;
import com.gm.wj.util.MyPage;
import com.gm.wj.util.MyTime;
import com.gm.wj.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @program: wj
 * @description: 订单与流水合并
 * @author: Huang_shengjun
 * @create: 2020-08-31 23:45
 **/
@Slf4j
@Service
public class SysOrderFlowService {

    @Autowired
    SysOrderDAO sysOrderDAO;
    @Autowired
    SysCourseService sysCourseService;
    @Autowired
    SysFlowDAO sysFlowDAO;
    @Autowired
    RedisService redisService;
    @Autowired
    AdminPermissionService adminPermissionService;
    @Autowired
    PermissionURL permissionURL;

    // status 为 0-单独购买；1-拼团；2-参团
    @Transactional
    public Map<String,String> addOrder(int id, String username, int status){
        Map<String, String> map = new HashMap<String, String>();
        try {
            SysCourse sysCourse = sysCourseService.findById(id);

            // 根据用户名、课程id查询。这个人是否报了名
            int isNum = isJoinByOrder(sysCourse.getCourseId(),username);
            if (isNum > 0) {
                log.info("{} 他已经报名了。拒绝再给你报名。",isNum);
                map.put("code", "401");
                map.put("message", "你已经报名了，不允许重复报名");
                return map;
            }
            // 根据用户名、课程id查询。这个人是否报了名 却没有支付 、待支付状态的，也不给他报名
            int isPay = isPayByOrder(sysCourse.getCourseId(),username);
            if (isPay > 0) {
                map.put("code", "401");
                map.put("message", "该课程下有待支付的订单。请前往支付。");
                return map;
            }

            SysOrder sysOrder = new SysOrder();
            sysOrder.setOrderId(StringUtils.generateOrderNo()); // 订单号
            sysOrder.setUsername(username);
            sysOrder.setOrderStatus(0);// 订单状态；0-待支付，1-已支付，2-已过期
            sysOrder.setOrderAmount(sysCourse.getCourseTuition());// 订单金额  课程学费
            sysOrder.setProductId(sysCourse.getCourseId());// 产品主键ID
            // 插入当前时间
            sysOrder.setCreateTime(MyTime.getStringDate());
            SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            // 插入设定的失效时间  可以是天数-days、小时-hours、分钟-minutes、秒-second
            sysOrder.setEndTime(MyTime.dateToStrLong(MyTime.getBeforeTime(myFormatter.format(new Date()), "yyyy-MM-dd HH:mm:ss", "minutes", 15)));
            String productName = sysCourse.getCourseName();

            SysCourse sysCourse1 = sysCourseService.findByCourseId(sysCourse.getCourseId());
            if (status == 0) {
                if (sysCourse1.getNum() - 1 < 0) {  // 库存为1时，减为0 ，可以继续执行
                    log.info("【单独购买】 {}  课程库存已经没了", sysCourse1.getCourseId());
                    // log.info("--进入手动事务回滚--" );
                    // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

                    map.put("code", "400");
                    map.put("message", "来迟了~课程库存没了");
                    return map;
                } else {
                    // 单独购买，扣除1个库存
                    log.info("【单独购买】，扣除【1】个库存");
                    sysCourseService.deductionStock(sysCourse.getCourseId(), 1);
                }
            }
            if (status == 1) {
                productName = "【拼团】" + productName;
                sysOrder.setOrderAmount(sysCourse.getPtTuition());
                if (sysCourse1.getNum() - 3 < 0) {  // 减为0 ，可以继续执行
                    log.info("【拼团】{}  课程库存已经没了", sysCourse1.getCourseId());
                    // log.info("--进入手动事务回滚--" );
                    // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

                    map.put("code", "400");
                    map.put("message", "来迟了~课程库存没了");
                    return map;
                } else {
                    // 开团，扣除3个库存
                    log.info("【开团】，扣除【3】个库存");
                    sysCourseService.deductionStock(sysCourse.getCourseId(), 3);
                }
            }
            if (status == 2) {
                productName = "【参团】" + productName;
                sysOrder.setOrderAmount(sysCourse.getPtTuition());
                log.info("开始有参团的订单了--->" + productName);
            }
            // 设置订单缓存
            String key = "ordersList:" + sysOrder.getOrderId();
            redisService.set(key, JsonUtils.objectToJson(sysOrder), RedisConfig.REDIS_KEY_TIME);  // 单位s 设置15分钟后过期
            sysOrder.setProductName(productName);

            SysOrder sysOrder1 = sysOrderDAO.save(sysOrder);
            // 返回生成的订单信息
            map.put("orderId", sysOrder1.getOrderId());
            map.put("code", "200");
            map.put("message", "生成订单成功");
            return map;
        } catch (Exception e){
            map.put("code", "400");
            map.put("message", "生成订单失败，错误："+ e.getMessage());
            return map;
        }
    }

    // 订单列表
    public MyPage list(int page, int size, String queryKey1, String queryKey2, String queryKey3) {
        // 获取操作用户名
        String username = (String) SecurityUtils.getSubject().getPrincipal();
        MyPage<SysOrder> orders;
        // list缓存
        String key = username + "orderspage:" + page;
        Object ordersPageCache = redisService.get(key);

        // 如果为空，就再查询一次，写入redis缓存
        if (ordersPageCache == null) {
            Sort sort = Sort.by(Sort.Direction.DESC, "id");
            Page<SysOrder> bannerInDb;

            // 重写 findAll方法  多条件查询
            Pageable pageable = new PageRequest(page, size,sort);
            Page<SysOrder> InDb = sysOrderDAO.findAll((Specification<SysOrder>) (root, criteriaQuery, criteriaBuilder) -> {
                List<javax.persistence.criteria.Predicate> list = new ArrayList<javax.persistence.criteria.Predicate>();
                // 实体类字段，不是数据库字段
                list.add(criteriaBuilder.equal(root.get("username").as(String.class), username));
                // 如果拥有权限  清除只能查询自己的数据的条件查询
                if(permissionURL.isPermissionURL(SysOrder.class.getSimpleName(),username)){
                    list.removeAll(list);
                }
                if(!"".equals(queryKey1)&&null!=queryKey1){
                    list.add(criteriaBuilder.like(root.get("orderStatus").as(String.class), "%" + queryKey1 + "%"));
                }
                if(!"".equals(queryKey2)&&null!=queryKey2){
                    list.add(criteriaBuilder.like(root.get("productName").as(String.class), "%" + queryKey2 + "%"));
                }
                if(!"".equals(queryKey3)&&null!=queryKey3){
                    list.add(criteriaBuilder.like(root.get("orderId").as(String.class), "%" + queryKey3 + "%"));
                }
                javax.persistence.criteria.Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            },pageable);
            // findAll方法 重写结束

            orders = new MyPage<>(InDb);
            // 设置redis过期时间  5s
            redisService.set(key, orders,RedisConfig.DATA_REDIS_KEY_TIME);
        } else {
            orders = (MyPage<SysOrder>) ordersPageCache;
        }
        return orders;
    }

    public SysFlow addFlow(SysFlow sysFlow){
        return sysFlowDAO.save(sysFlow);
    }

    public SysOrder onlyAddOrder(SysOrder sysOrder){
        return sysOrderDAO.save(sysOrder);
    }

    public SysOrder findById(int id) {
        SysOrder sysOrder;
        String key = "order:" + id;
        Object orderCache = redisService.get(key);

        if (orderCache == null) {
            sysOrder = sysOrderDAO.findById(id);
            redisService.set(key, sysOrder,RedisConfig.DATA_REDIS_KEY_TIME);
        } else {
            sysOrder = (SysOrder) orderCache;
        }
        return sysOrder;
    }

    public SysOrder findByOrderId(String id) {
        SysOrder sysOrder;
        String key = "order:" + id;
        Object orderCache = redisService.get(key);

        if (orderCache == null) {
            sysOrder = sysOrderDAO.findByOrderId(id);
            redisService.set(key, sysOrder,RedisConfig.DATA_REDIS_KEY_TIME);
        } else {
            sysOrder = (SysOrder) orderCache;
        }
        return sysOrder;
    }

    public boolean findByTradeNo(String out_trade_no) {
       if(sysFlowDAO.findByTradeNo(out_trade_no) == 0){
           return true;
       }else {
           return false;
       }
    }

    public SysOrder findSysOrderByOrderId(String out_trade_no) {
        return sysOrderDAO.findSysOrderByOrderId(out_trade_no);
    }

    public void editOrder(SysOrder sysOrder) {
         sysOrderDAO.save(sysOrder);
    }

    public Object listByQueryKey(String queryKey1, String queryKey2, String queryKey3,String username) {
        // 多条件模糊查询
//        queryKey1 = (queryKey1 == null && queryKey1 == "" ) ? null : "" + queryKey1 + ""; // booble值  直接用等于  不用like了
        queryKey1 = (queryKey1 == null) ? null : "%" + queryKey1 + "%";
        queryKey2 = (queryKey2 == null) ? null : "%" + queryKey2 + "%";
        queryKey3 = (queryKey3 == null) ? null : "%" + queryKey3 + "%";
        username = (username == null) ? null : "%" + username + "%";
        List<SysOrder> sysOrders = sysOrderDAO.find(queryKey1, queryKey2, queryKey3,username);

        return sysOrders;
    }

    /**
     * 更改订单状态
     * @param i
     * @param sysOrder
     */
    public void setStatusByOrder(int i, SysOrder sysOrder) {
        sysOrder.setOrderStatus(i);
        sysOrderDAO.save(sysOrder);
    }

    /**
     * 根据用户名、课程id查询。这个人是否报了名
     * @param orderId
     * @param username
     * @return
     */
    public int isJoinByOrder(String orderId,String username){
        return sysOrderDAO.isJoinByOrder(orderId,username);
    }

    /**
     * 根据用户名、课程id查询。这个人是否有待支付的订单。有的话让他先支付，不要报名了
     * @param orderId
     * @param username
     * @return
     */
    public int isPayByOrder(String orderId,String username){
        return sysOrderDAO.isPayByOrder(orderId,username);
    }

    /**
     * 根据订单id查找流水单
     * @param orderId
     * @return
     */
    public SysFlow findSysFlowByOrderId(String orderId){
        return sysFlowDAO.findByOrderId(orderId);
    }

    public MyPage Flowlist(int page, int size,String queryKey1) {
        // 获取操作用户名
        String username = (String) SecurityUtils.getSubject().getPrincipal();
        MyPage<SysFlow> sysFlows;
        // list缓存
        String key =  username + "flowpage:" + page;
        Object PageCache = redisService.get(key);

        // 如果为空，就再查询一次，写入redis缓存
        if (PageCache == null) {
            Sort sort = Sort.by(Sort.Direction.DESC, "id");

            // 重写 findAll方法  多条件查询

            Pageable pageable = new PageRequest(page, size,sort);
            Page<SysFlow> InDb = sysFlowDAO.findAll((Specification<SysFlow>) (root, criteriaQuery, criteriaBuilder) -> {
                List<javax.persistence.criteria.Predicate> list = new ArrayList<javax.persistence.criteria.Predicate>();
                // 实体类字段，不是数据库字段
                list.add(criteriaBuilder.equal(root.get("username").as(String.class), username));
                // 如果拥有权限  清除只能查询自己的数据的条件查询
                if(permissionURL.isPermissionURL(SysFlow.class.getSimpleName(),username)){
                    list.removeAll(list);
                }
                if(!"".equals(queryKey1)&&null!=queryKey1){
                    list.add(criteriaBuilder.like(root.get("orderId").as(String.class), "%" + queryKey1 + "%"));
                }
                javax.persistence.criteria.Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            },pageable);
            // findAll方法 重写结束

            sysFlows = new MyPage<>(InDb);
            // 设置redis过期时间  5s
            redisService.set(key, sysFlows,RedisConfig.DATA_REDIS_KEY_TIME);
        } else {
            sysFlows = (MyPage<SysFlow>) PageCache;
        }
        return sysFlows;
    }

    /**
     * 课程售出数量折线图
     * @return
     */
    public List<Object> findFlowByBuy() {
        return sysFlowDAO.findFlowByBuy();
    }

    /**
     * 收入类型图（拼团）
     * @return
     */
    public int findAllByPtStatus() {
        return sysOrderDAO.findAllByPtStatus();
    }

    /**
     * 收入类型图（单买）
     */
    public int findAllBydmStatus() {
        return sysOrderDAO.findAllBydmStatus();
    }

    /**
     * 收入类型图（现金）
     * @return
     */
    public int findAllByxj() {
        return sysFlowDAO.countByIsPay(1);
    }

    public List<Object> findFlowByMoney() {
        return sysFlowDAO.findFlowByMoney();
    }

    public List<SysOrder> findOrderByUsername(String username) {
        return sysOrderDAO.findFlowByUsername(username);
    }

    public List<SysOrder> findOrderByCourseId(String courseId) {
        return sysOrderDAO.findAllByProductId(courseId);
    }
}
